package org.btik.lightweb.client.login;


import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.btik.light.server.platform.common.api.bean.common.StatusResult;
import org.btik.light.server.platform.common.api.bean.login.LoginDto;
import org.btik.light.server.platform.common.api.bean.login.LoginResult;
import org.btik.light.server.platform.common.api.bean.login.LoginStatus;
import org.btik.light.server.platform.common.api.bean.sensitive.DhPublicKey;
import org.btik.light.server.platform.common.api.bean.sensitive.annotation.SensitiveBody;
import org.btik.light.server.platform.common.api.bean.user.UserVo;
import org.btik.light.server.platform.common.api.service.LoginService;
import org.btik.light.server.platform.common.api.service.SensitiveDataService;
import org.btik.light.tool.DhUtil;
import org.btik.light.tool.type.StringUtil;
import org.btik.lightweb.util.WebUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import java.io.IOException;

import static org.btik.light.server.platform.common.api.bean.common.ResultFactory.failed;
import static org.btik.light.tool.ByteUtil.encode2Base64Str;

/**
 * @author lustre
 * @since 2023/6/11 13:59
 */
@RestController
@RequestMapping("/login")
public class LoginController {

    @Autowired
    private LoginService loginService;

    @Autowired
    private SensitiveDataService sensitiveDataService;

    public static final String CURRENT_USER = "CURRENT_USER";

    public static final String DH_KEY_PAIR = "DH_KEY_PAIR";

    public static final String SESSION_KEY = "SESSION_KEY";

    @GetMapping("/captcha")
    public void captcha(HttpSession session, HttpServletResponse response) throws IOException {

        response.setHeader("Pragma", "no-cache");
        response.addHeader("Cache-Control", "must-revalidate");
        response.addHeader("Cache-Control", "no-cache");
        response.addHeader("Cache-Control", "no-store");
        response.setDateHeader("Expires", 0);
        response.setHeader("Access-Control-Allow-Credentials", "true");

        String code = CaptchaGenerator.outputVerifyImage(400, 200, response.getOutputStream(), 4);
        session.setMaxInactiveInterval(3 * 60);
        session.setAttribute("code", code);
    }

    @PostMapping("/doLogin")
    public StatusResult<LoginResult> login(@SensitiveBody(userSession = false) LoginDto loginDto, HttpSession session, HttpServletRequest httpServletRequest) {
        String code = (String) session.getAttribute("code");
        if (StringUtil.isEmpty(code)) {
            return failed(LoginStatus.TIMEOUT);
        }
        // 销毁验证码的会话
        session.invalidate();

        String ip = WebUtil.getIpAddr(httpServletRequest);

        StatusResult<LoginResult> loginResult = loginService.login(ip, code, loginDto);
        if (!loginResult.isSuccess()) {
            return loginResult;
        }
        // 新建会话保存用户和dh公私钥对
        session = httpServletRequest.getSession(true);
        session.setAttribute(CURRENT_USER, loginResult.getResult().getUser());
        session.setAttribute(SESSION_KEY, WebUtil.getRequestFrom(httpServletRequest));
        // 重新生成新的公私钥对，公钥才登录结果里发给前端
        DhUtil.DhKeyPair dhKeyPair = sensitiveDataService.generateKeyPair();
        DHPublicKey publicKey = dhKeyPair.getPublicKey();
        DHParameterSpec params = publicKey.getParams();
        DhPublicKey dhPublicKey = new DhPublicKey(
                encode2Base64Str(publicKey.getY().toByteArray()),
                encode2Base64Str(params.getP().toByteArray()),
                encode2Base64Str(params.getG().toByteArray()), null);
        loginResult.getResult().setDhPublicKey(dhPublicKey);
        //保存当前公私钥对到用户会话
        session.setAttribute(DH_KEY_PAIR, dhKeyPair);
        return loginResult;
    }

    @GetMapping("/isLogin")
    public boolean isLogin(HttpSession session) {
        UserVo loginUser = (UserVo) session.getAttribute(CURRENT_USER);
        return loginUser != null
                && loginUser.isEnable();
    }

    @GetMapping("/logout")
    public boolean logout(HttpSession session) {
        session.invalidate();
        return true;
    }

    @GetMapping("/token")
    public String token() {
        return loginService.token();
    }
}
